package org.onion.pattern.event.consumer;


import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.onion.pattern.event.exception.EventConsumeException;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;

@Slf4j
public final class InterceptableEventConsumeHandler implements EventConsumeHandler {

    @Getter
    private final EventConsumeHandler           agencyHandler;
    @Getter
    private final List<EventConsumeInterceptor> interceptors;

    public InterceptableEventConsumeHandler(EventConsumeHandler agencyHandler, List<EventConsumeInterceptor> interceptors) {
        this.agencyHandler = agencyHandler;
        interceptors = ObjectUtils.defaultIfNull(interceptors, new ArrayList<>());
        interceptors.sort(Comparator.comparingInt(EventConsumeInterceptor::order));
        this.interceptors = new CopyOnWriteArrayList<>(interceptors);
    }

    @Override
    public final Object consumerGroup() {
        return agencyHandler.consumerGroup();
    }

    @Override
    public final Class<?> consumerGroupClass() {
        return agencyHandler.consumerGroupClass();
    }

    @Override
    public final void handle(ExternalEventInfo eventInfo, Object metadata) throws EventConsumeException {
        if (CollectionUtils.isEmpty(interceptors)) {
            this.agencyHandler.handle(eventInfo, metadata);
        }

        Exception ex = null;
        boolean canHandle = true;

        //预处理
        int index = 0;
        try {
            for (int i = 0; i < interceptors.size(); i++) {
                EventConsumeInterceptor interceptor = interceptors.get(index);
                canHandle = interceptor.preHandle(eventInfo, metadata, agencyHandler);
                if (!canHandle) {
                    break;
                }
            }
        } catch (Exception e) {
            canHandle = false;
            ex = e;
        }

        //跳过处理
        if (!canHandle) {
            for (; index >= 0; index--) {
                EventConsumeInterceptor interceptor = interceptors.get(index);
                try {
                    interceptor.afterCompletion(eventInfo, metadata, agencyHandler, ex);
                } catch (Throwable e) {
                    log.error("", e);
                }
            }

            //如果有异常就向外报出
            if (ex != null) {
                if (ex instanceof EventConsumeException) {
                    throw (EventConsumeException) ex;
                }
                throw new EventConsumeException(ex);
            }

            return;
        }

        //处理真正的逻辑
        try {
            this.agencyHandler.handle(eventInfo, metadata);
        } catch (Exception e) {
            ex = e;
        }

        //post 处理, this.agencyHandler.handle 处理成功之时处理
        if (ex == null) {
            try {
                for (int i = index; i >= 0; i--) {
                    EventConsumeInterceptor interceptor = interceptors.get(index);
                    interceptor.postHandle(eventInfo, metadata, agencyHandler);
                }
            } catch (Exception e) {
                ex = e;
            }
        }


        // after 处理
        for (; index >= 0; index--) {
            EventConsumeInterceptor interceptor = interceptors.get(index);
            try {
                interceptor.afterCompletion(eventInfo, metadata, agencyHandler, ex);
            } catch (Throwable e) {
                log.error("", e);
            }
        }

        //如果有异常就向外报出
        if (ex != null) {
            if (ex instanceof EventConsumeException) {
                throw (EventConsumeException) ex;
            }
            throw new EventConsumeException(ex);
        }

    }


}
